package com.plian.system.service.wf;

import com.alibaba.fastjson.JSON;
import com.plian.Tools.CollectionUtil;
import com.plian.Tools.StringUtil;
import com.plian.Tools.TokenUtil;
import com.plian.Tools.UuidUtil;
import com.plian.Tools.pagedata.PageData;
import com.plian.system.bean.wf.TaskWithForm;
import com.plian.system.bean.wf.UserPOJO;
import com.plian.system.bean.wf.UserTaskPOJO;
import com.plian.system.config.exception.MyRuntimeException;
import com.plian.system.constant.sys.FormStatusConstant;
import com.plian.system.constant.wf.TaskStateConstant;
import com.plian.system.constant.wf.WorkflowConstant;
import com.plian.system.dao.sys.orgzation.OrgzationDao;
import com.plian.system.dao.sys.orgzation.UserGroupRelationDao;
import com.plian.system.dao.wf.WfCompletedTaskMapper;
import com.plian.system.helper.wf.SimulationHelper;
import com.plian.system.helper.wf.WorkFlowHelper;
import com.plian.system.helper.wf.WorkflowProcessListHelper;
import com.plian.system.model.CommonCode;
import com.plian.system.model.ListResult;
import com.plian.system.model.ObjResult;
import com.plian.system.model.page.Page;
import com.plian.system.service.sys.orgzation.OrgzationService;
import com.plian.system.service.sys.user.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.engine.*;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.flowable.task.service.impl.persistence.entity.TaskEntity;
import org.flowable.task.service.impl.persistence.entity.TaskEntityImpl;
import org.flowable.ui.modeler.domain.ApprovalPoints;
import org.flowable.ui.modeler.domain.Privilege;
import org.flowable.ui.modeler.service.PrivilegeService;
import org.flowable.variable.api.history.HistoricVariableInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;

import static com.plian.system.constant.wf.WorkflowConstant.*;

@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Slf4j
@Service
@Transactional
public class WorkflowServiceImpl implements WorkflowService {
    @Autowired
    @Qualifier("processEngine")
    private ProcessEngine processEngine;

    @Autowired
    private RuntimeService runtimeService;

    @Autowired
    private TaskService taskService;

    @Autowired
    private ManagementService managementService;

    @Autowired
    private HistoryService historyService;

    @Autowired
    private WorkFlowHelper workFlowHelper;

    @Autowired
    private SimulationHelper simulationHelper;

    @Autowired
    private UserService userService;

    @Autowired
    private WorkFlowFormService workFlowFormService;

    @Autowired
    private UserGroupRelationDao userGroupRelationDao;

    @Autowired
    private OrgzationDao orgzationDao;

    @Autowired
    private PrivilegeService privilegeService;

    @Autowired
    private WfCompletedTaskMapper wfCompletedTaskMapper;

    @Autowired
    private OrgzationService orgzationService;
    @Autowired(
            required = false
    )
    private SimulationHelperTwo simulationHelperTwo;
    @Override
    public void submit(String formId, int formType, Map<String, Object> variables) {
        startProcessInstanceByKeyAndTenantId(formId, formType, variables, TokenUtil.getTokenUserId());
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(formId)
                .singleResult();
        Task task;
        List<Task> taskList = taskService.createTaskQuery().processInstanceId(processInstance.getId()).list();
        if (taskList.size() != 1) {
            throw new MyRuntimeException(new ObjResult("任务不唯一"));
        }
        task = taskList.get(0);
        String comment;
        if (formType == 1 && variables.get("reason") != null) {
            comment = variables.get("reason").toString();
        } else {
            comment = FIRST_TASK_COMMENT;
        }
        variables.put(SET_NUMBER, 1);

        String taskId = task.getId();
        taskService.addComment(taskId, task.getProcessInstanceId(), String.valueOf(TaskStateConstant.STATE_APPLIED));
        Map<String, Object> oldVariable = runtimeService.getVariables(processInstance.getId());
        oldVariable.putAll(variables);
        runtimeService.setVariables(processInstance.getId(), oldVariable);
        // 在提交表单之后 模拟工作流流程数据
        List<UserTaskPOJO> userTaskPOJOS;
        // fix 如果单据是退回重现提交的单据 要保留之前的审批过程
        if (oldVariable.containsKey(USER_TASK_INFO_KEY)) {
            /*if(formType==50104||formType==132001||formType==132002||formType==50094){//特殊处理可以三级企业和二级企业可以直接到国资委
                WorkflowProcessListHelperTwo helper = new WorkflowProcessListHelperTwo(workFlowHelper.getUserTaskListInProcessVariable(oldVariable), workFlowHelper, processInstance.getId());
                userTaskPOJOS = helper.submitAfterReturnFirst(simulationHelperTwo, processInstance, comment, new UserPOJO(userService.getCurrentUser()));
            }else{*/
                WorkflowProcessListHelper helper = new WorkflowProcessListHelper(workFlowHelper.getUserTaskListInProcessVariable(oldVariable), workFlowHelper, processInstance.getId());
                userTaskPOJOS = helper.submitAfterReturnFirst(simulationHelper, processInstance, comment, new UserPOJO(userService.getCurrentUser()));
            /*}*/

        } else {
            LinkedList<UserTaskPOJO> userTaskPOJOLinkedList=new LinkedList<>();
           /* if(formType==50104||formType==132001||formType==132002||formType==50094){//特殊处理可以三级企业和二级企业可以直接到国资委
                userTaskPOJOLinkedList = simulationHelperTwo.simulation(processInstance, oldVariable, true);
            }else{*/
                userTaskPOJOLinkedList = simulationHelper.simulation(processInstance, oldVariable, true);
            /*}*/

            //List<UserTaskPOJO> userTaskPOJOLinkedList = workFlowHelper.getUserTaskListInProcessVariable(oldVariable);
            WorkflowProcessListHelper helper = new WorkflowProcessListHelper(userTaskPOJOLinkedList, workFlowHelper, processInstance.getId());
            userTaskPOJOS = helper.agreeOrSubmit(comment, new UserPOJO(userService.getCurrentUser()));
        }
        workFlowHelper.saveUserTaskListIntoVariable(userTaskPOJOS, processInstance.getId());
        taskService.complete(taskId);
    }

    @Override
    public void startProcessInstanceByKeyAndTenantId(String formId, int formType, Map<String, Object> variables, String startUserId) {
       /* List<PageData> pageData = workFlowFormService.get(formType, formId);
        if ("0".equals(pageData.get(0).get("status"))) {
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(formId).singleResult();
            if (historicProcessInstance != null) {
                runtimeService.deleteProcessInstance(historicProcessInstance.getId(), "");
                historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
            }
        }*/

        // 保证formId 和 processInstanceId 一一对一
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(formId).list();
        if (CollectionUtil.isNotEmpty(list)) {
            return;
        }

        //放入全局的流程变量

        List<PageData> pageDataList = workFlowFormService.get(formType, formId, variables.containsKey(CODE) ? (String)variables.get(CODE) : null);
        if (CollectionUtil.isNotEmpty(pageDataList)) {
            pdToVariables(pageDataList.get(0), variables, startUserId);
        }
        variables.put(FORM_TYPE, formType);
        variables.put(APPLICANT_ID, TokenUtil.getTokenUserId());
        PageData pd = null;
        try {
            pd = orgzationDao.findbyid(TokenUtil.getTokenOrgId());
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult("无法获取当前登录用户的单位！"));
        }
        try {
            PageData groupOrg = orgzationService.getGroupbyId(pd.getString("id"), orgzationDao.list(null));
            if(groupOrg == null){
                groupOrg = pd;
            }
            variables.put(UNIT_ORG_ID, groupOrg.getString("id"));
        }catch (Exception e){
            log.error("---> 获取集团id失败");
        }
        variables.put("organizationId", pd.getString("id"));
        variables.put("virtualNode", "false");
        if (pd.getInteger("type") == 2) {
            int grade = getOrganizationLevel(pd, 0);
            variables.put("organizationLevel", String.valueOf(grade));
        } else if (pd.getInteger("type") == 1) {
            variables.put("organizationLevel", "0");
        }else if (pd.getInteger("type") == 3) {
            //虚拟节点
            variables.put("virtualNode", "true");
        }
        if(formType==55){//职工工资特殊处理
            if(pd.getInteger("type") == 4){
                variables.put("organizationLevel", "0");
            }
        }

        startProcessInstanceByKeyAndTenantId(workFlowHelper.getModelKeyWithFormType(formType), formId, variables, startUserId);
    }

    public void startProcessInstanceForBackToStash(String formId, int formType, Map<String, Object> variables, String startUserId) {
        // 保证formId 和 processInstanceId 一一对一
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(formId).list();
        if (CollectionUtil.isNotEmpty(list)) {
            return;
        }
        startProcessInstanceByKeyAndTenantId(workFlowHelper.getModelKeyWithFormType(formType), formId, variables, startUserId);
    }

    /**
     * 获取企业的级次
     *
     * @param pd    单位
     * @param grade 级次
     * @return 企业的级次
     */
    private int getOrganizationLevel(PageData pd, int grade) {
        try {
            String parentId = pd.getString("parentId");
            PageData parent = orgzationDao.findbyid(parentId);
            if (parent.getInteger("type") == 0 || parent.getInteger("type") == 1 || parent.getInteger("type") == 4) {
                return grade + 1;
            } else if (parent.getInteger("type") == 2) {
                return getOrganizationLevel(parent, grade + 1);
            } else if (parent.getInteger("type") == 3) {
                return getOrganizationLevel(parent, grade);
            }
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
        }
        return grade;
    }

    public void startProcessInstanceByKeyAndTenantId(String processDefinitionKey, String businessKey, Map<String, Object> variables, String startUserId) {
        // 默认当前单位的工作流
        ProcessInstance processInstance;
        // 判断表单是否被发起过
        List<ProcessInstance> list = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(businessKey)
                .list();
        if (CollectionUtil.isNotEmpty(list)) {
            if (list.size() == 1) {
                processInstance = list.get(0);
            } else {
                throw new MyRuntimeException(new ObjResult("当前单据存在多个流程，请联系管理员维护数据库！"));
            }
        } else {
            try {
                String orgId = (String)variables.get(ORGANIZATION_ID);
                PageData groupOrg = orgzationService.getGroupbyId(orgId, orgzationDao.list(null));
                if(groupOrg == null){
                    variables.put(UNIT_ORG_ID, orgId);
                }else {
                    variables.put(UNIT_ORG_ID, groupOrg.getString("id"));
                }

            }catch (Exception e){
                log.error("---> 获取集团id失败");
            }
            processEngine.getIdentityService().setAuthenticatedUserId(startUserId == null ? userService.getCurrentUser().getId() : startUserId);
            processInstance = runtimeService.startProcessInstanceByKeyAndTenantId(processDefinitionKey, businessKey, variables, null);
        }
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        taskService.setAssignee(task.getId(), startUserId == null ? userService.getCurrentUser().getId() : startUserId);
        taskService.setVariableLocal(task.getId(), APPLY_STATE, TaskStateConstant.STATE_NO_APPLY);
    }

    @Override
    public List<TaskWithForm> getTodoTaskListByUserId(String userId, String organizationId) throws Exception {
        List<Task> taskList = new ArrayList<>();
        List<TaskWithForm> taskWithFormList = new ArrayList<>();
        PageData pageData = new PageData();
        pageData.put("userId", userId);
        pageData.put("organizationId", organizationId);
        List<String> groupList = userGroupRelationDao.getGroupIdListByUserIdAndOrganizationId(pageData).stream().map(item -> item.getString("group_id")).collect(Collectors.toList());
        List<Task> groupTaskList = null;
        if (CollectionUtil.isNotEmpty(groupList)) {
            groupTaskList = taskService.createTaskQuery()
                    .includeIdentityLinks()
                    .taskCandidateGroupIn(groupList)
                    .includeProcessVariables()
                    .orderByTaskCreateTime()
                    .desc()
                    .active()
                    .list();
            groupTaskList.removeIf(task -> {
                if ("before-parent".equals(task.getScopeType())) {
                    return true;
                }
                //获取组织名称
                String organization = getOrganization(task);
                if (StringUtils.isEmpty(organization)) {
                    return true;
                }
                return !organization.equals(organizationId);
            });
        }
        if (groupTaskList != null) {
            taskList.addAll(groupTaskList);
        }
        Set<String> orgProcInstIds = taskList.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
        if (CollectionUtils.isNotEmpty(orgProcInstIds)) {
            List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().processInstanceIds(orgProcInstIds).list();
            processInstanceList.forEach(hpi -> taskList.forEach(task -> {
                if (task.getProcessInstanceId().equals(hpi.getId())) {
                    TaskWithForm taskWithForm = new TaskWithForm(task, hpi);
                    taskWithForm.setTaskState(TaskStateConstant.STATE_TODO);
                    taskWithFormList.add(taskWithForm);
                }
            }));
        }
        // assignee
        List<Task> assigneeList = taskService.createTaskQuery()
                .or()
                .taskAssignee(userId)
                .taskCandidateUser(userId)
                .endOr()
                .includeProcessVariables()
                .active()
                .list();
        assigneeList.removeIf(task -> {
            if ("before-parent".equals(task.getScopeType())) {
                return true;
            }
            return false;
        });
        if (assigneeList.size() > 0) {
            taskList.addAll(assigneeList);
            Set<String> procInstIds = assigneeList.stream().map(Task::getProcessInstanceId).collect(Collectors.toSet());
            Set<String> taskIds = assigneeList.stream().map(Task::getId).collect(Collectors.toSet());
            Map<String, List<HistoricVariableInstance>> taskIdVariableListMap = historyService
                    .createHistoricVariableInstanceQuery()
                    .excludeVariableInitialization()
                    .taskIds(taskIds)
                    .variableName(WorkflowConstant.APPLY_STATE)
                    .list().stream().collect(Collectors.groupingBy(HistoricVariableInstance::getTaskId));
            List<HistoricProcessInstance> processInstanceList = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceIds(procInstIds).list();
            for (HistoricProcessInstance hpi : processInstanceList) {
                for (Task task : assigneeList) {
                    if (task.getProcessInstanceId().equals(hpi.getId())) {
                        Map<String, Object> processVariables = hpi.getProcessVariables();
                        boolean refuseFlag = false;
                        if (processVariables.containsKey(USER_TASK_INFO_KEY)) {
                            List<UserTaskPOJO> userTaskList = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
                            for(int i=0; i<userTaskList.size();i++)
                            {
                                if(userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_BACK_TO_STASH||
                                        userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_REFUSE||
                                        userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_TURN_BACK||
                                        userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_APPLIED)
                                {
                                    refuseFlag = true;
                                    break;
                                }
                            }

                        }
                        TaskWithForm taskWithForm = new TaskWithForm(task, hpi);
                        List<HistoricVariableInstance> taskVariableList = new ArrayList<>();
                        if (taskIdVariableListMap.containsKey(task.getId())){
                            taskVariableList = taskIdVariableListMap.get(task.getId());
                        }
                        if ((task.getName() != null && (task.getName().contains("申请") || task.getName().contains("提交") || task.getName().contains("上报") || task.getName().contains("发起")))
                                || (CollectionUtils.isNotEmpty(taskVariableList))) {
//                            taskWithForm.setTaskState(TaskStateConstant.STATE_NO_APPLY);
                            if (refuseFlag){
                                taskWithForm.setTaskState(TaskStateConstant.STATE_REFUSE);
                                // 驳回的话
                                String organization = getOrganization(task);
                                if (StringUtils.isEmpty(organization)){
                                    taskWithFormList.add(taskWithForm);
                                }else {
                                    String orgId = TokenUtil.getTokenOrgId();
                                    if (organization.equals(orgId)){
                                        taskWithFormList.add(taskWithForm);
                                    }
                                }

                            }

                        } else {
                            taskWithForm.setTaskState(TaskStateConstant.STATE_TODO);
                            taskWithFormList.add(taskWithForm);
                        }

                    }
                }
            }
        }
        taskWithFormList.sort((o1, o2) -> new Date(o2.getTaskCreateTime()).compareTo(new Date(o1.getTaskCreateTime())));
        return taskWithFormList;
    }

    private String getOrganization(Task task){
        Map<String, Object> taskProcessVariables = task.getProcessVariables();
        List<UserTaskPOJO> userTaskList = workFlowHelper.getUserTaskListInProcessVariable(taskProcessVariables);
        String organization = "";
        if (CollectionUtil.isNotEmpty(userTaskList)) {
            List<UserTaskPOJO> filterUserTask = userTaskList.stream().filter(item -> item.getTaskDefineId().equals(task.getTaskDefinitionKey())).collect(Collectors.toList());
            if (filterUserTask.size() > 0) {
                organization = filterUserTask.get(filterUserTask.size() -1).getBelongedOrganizationId();
            }
        }
        return organization;
    }

    @Override
    public void clearOldUnWorkFlow(int formType, String formId)
    {
        // List<PageData> pageData = workFlowFormService.get(formType, formId);
        // System.out.print("clearOldUnWorkFlow");
        // System.out.println(pageData.get(0).get("status"));
        //if ("0".equals(pageData.get(0).get("status"))) {
        if(true){
            System.out.print("2clearOldUnWorkFlow");
            HistoricProcessInstance historicProcessInstance = historyService.createHistoricProcessInstanceQuery().includeProcessVariables().processInstanceBusinessKey(formId).singleResult();
            if (historicProcessInstance != null) {

                boolean canDeleteOldFlow=true;

                //判断是否已经有上级处理过，驳回状态和反审核状态不再处理
                Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
                System.out.println("print json"+JSON.toJSONString(processVariables));

                if (processVariables.containsKey(USER_TASK_INFO_KEY)) {
                    List<UserTaskPOJO> userTaskList = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
                    System.out.println("userTaskList size:"+userTaskList.size());
                    for(int i=0; i<userTaskList.size();i++)
                    {
                        System.out.println(userTaskList.get(i).getTaskState());
                        if(userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_BACK_TO_STASH||
                                userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_REFUSE||
                                userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_TURN_BACK||
                                userTaskList.get(i).getTaskState()==TaskStateConstant.STATE_APPLIED)
                        {
                            System.out.println("can not delete ,state:"+userTaskList.get(i).getTaskState());
                            canDeleteOldFlow=false;
                            break;
                        }
                    }

                }

                if(canDeleteOldFlow) {
                    runtimeService.deleteProcessInstance(historicProcessInstance.getId(), "");
                    historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());
                }
            }
        }
    }


    @Override
    public void rollBack(String formId) {
        // 当前界面上的taskId对应userTask实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(formId).includeProcessVariables().singleResult();
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        List<UserTaskPOJO> taskListInProcessVariable = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(taskListInProcessVariable, workFlowHelper, processInstance.getId());
        UserTaskPOJO currentNode = helper.getCurrentNode();
        List<UserTaskPOJO> pojoList = helper.rollBack(new UserPOJO(userService.getCurrentUser()));
        UserTaskPOJO firstPojo = taskListInProcessVariable.get(0);
        Task activeTask = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
        // 当前task assignee去掉，如果不去掉，下一个环节的待办列表里会出现这条被撤回的单据
        //taskService.unclaim(activeTask.getId());
        //activeTask.setDescription(String.valueOf(TaskStateConstant.STATE_ROLL_BACK));
        //taskService.saveTask(activeTask);
        taskService.addComment(activeTask.getId(), processInstance.getId(), String.valueOf(TaskStateConstant.STATE_ROLL_BACK));
        runtimeService.setVariable(processInstance.getId(), SET_NUMBER, 0);
        // 工作流数据的退回  即标识删除当前userTask 再创建上一个节点的userTask实例
        runtimeService
                .createChangeActivityStateBuilder()
                .processInstanceId(processInstance.getId())
                .moveActivityIdTo(activeTask.getTaskDefinitionKey(), currentNode.getTaskDefineId())
                .changeState();
        if (firstPojo.getTaskDefineId().equals(currentNode.getTaskDefineId())) {
            // 退回的是第一个节点
            try {
                workFlowFormService.reject((Integer) processVariables.get(FORM_TYPE), formId, FormStatusConstant.UNREVIEWED, "撤回");
                Task act = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();
                taskService.setAssignee(act.getId(), firstPojo.getUserList().get(0).getId());
            } catch (Exception e) {
                log.error(ExceptionUtils.getFullStackTrace(e));
                throw new MyRuntimeException(new ObjResult("撤回过程中改变单据状态失败！"));
            }
        }

        workFlowHelper.saveUserTaskListIntoVariable(pojoList, processInstance.getId());
    }

    @Override
    public void turnBack(String formId, String comment, List<ApprovalPoints> approvalPointsList) throws Exception {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().includeProcessVariables().processInstanceBusinessKey(formId)
                .singleResult();
        Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId()).singleResult();

        // 设置办理人 以便在完成列表中出现
        taskService.setAssignee(task.getId(), userService.getCurrentUser().getId());
        taskService.addComment(task.getId(), processInstance.getId(), String.valueOf(TaskStateConstant.STATE_TURN_BACK));
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        List<UserTaskPOJO> taskListInProcessVariable = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(taskListInProcessVariable, workFlowHelper, processInstance.getId());
        List<UserTaskPOJO> pojoList = helper.turnBack(comment, approvalPointsList, new UserPOJO(userService.getCurrentUser()), simulationHelper, processInstance, task);
        Task activeTask = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
        UserTaskPOJO targetNode = helper.getTurnBackNode();
        //activeTask.setDescription(String.valueOf(TaskStateConstant.STATE_TURN_BACK));
        //taskService.saveTask(activeTask);
        // 工作流数据的  退回  即标识删除当前userTask 再创建上一个节点的userTask实例
        runtimeService
                .createChangeActivityStateBuilder()
                .processInstanceId(task.getProcessInstanceId())
                .moveActivityIdTo(activeTask.getTaskDefinitionKey(), targetNode.getTaskDefineId())
                .changeState();
        workFlowHelper.saveUserTaskListIntoVariable(pojoList, task.getProcessInstanceId());
        UserTaskPOJO firstPojo = pojoList.get(0);
        if(processVariables.containsKey(SET_NUMBER)){
            if (firstPojo.getTaskDefineId().equals(targetNode.getTaskDefineId())) {
                runtimeService.setVariable(processInstance.getId(), SET_NUMBER, 0);
            }else {
                runtimeService.setVariable(processInstance.getId(), SET_NUMBER, (int)processVariables.get(SET_NUMBER) - 1);
            }
        }
        if (firstPojo.getTaskDefineId().equals(targetNode.getTaskDefineId())) {
            try {
                workFlowFormService.reject((Integer) processVariables.get(FORM_TYPE), formId, FormStatusConstant.REJECT, comment);
                Task first = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).singleResult();
                taskService.setAssignee(first.getId(), firstPojo.getUserList().get(0).getId());
            } catch (Exception e) {
                log.error(ExceptionUtils.getFullStackTrace(e));
                throw new MyRuntimeException(new ObjResult("退回至经办人时修改单据状态失败！"));
            }
        }
    }

    @Override
    public String returnFirst(String formId, String comment, List<ApprovalPoints> approvalPointsList) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(formId).includeProcessVariables().singleResult();
        if (processInstance == null) {
            throw new MyRuntimeException(new ObjResult("不存在该待办事项"));
        }
        String processInstanceId = processInstance.getId();
        Task task = taskService.createTaskQuery().taskDefinitionKey(processInstance.getActivityId()).processInstanceId(processInstanceId).singleResult();
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        // 历史的userTask 里面 按时间升序排序的第一个就是经办人申请节点
        HistoricTaskInstance historicTaskInstance = historyService
                .createHistoricTaskInstanceQuery()
                .processInstanceId(processInstanceId)
                .orderByHistoricTaskInstanceEndTime()
                .asc()
                .finished()
                .list()
                .get(0);
        assert historicTaskInstance != null;
        taskService.setAssignee(task.getId(), userService.getCurrentUser().getId());
        taskService.addComment(task.getId(), processInstance.getId(), String.valueOf(TaskStateConstant.STATE_REFUSE));
        //task.setDescription(String.valueOf(TaskStateConstant.STATE_REFUSE));
        //taskService.saveTask(task);
        // 维护工作流链表
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(workFlowHelper.getUserTaskListInProcessVariable(processVariables), workFlowHelper, processInstance.getId());
        runtimeService.setVariable(processInstance.getId(), SET_NUMBER, 0);
        workFlowHelper.saveUserTaskListIntoVariable(helper.returnFirst(approvalPointsList, comment, new UserPOJO(userService.getCurrentUser())), processInstanceId);
        // 结束（办理/逻辑删除/进入历史）当前任务 并且跳转到经办人（申请人）节点
        runtimeService.createChangeActivityStateBuilder()
                .processInstanceId(processInstanceId)
                .moveActivityIdTo(task.getTaskDefinitionKey(), historicTaskInstance.getTaskDefinitionKey())
                .changeState();
        // 设置申请环节的办理人
        Task newCurrentTask = taskService
                .createTaskQuery()
                .processInstanceId(processInstanceId)
                .list()
                .get(0);
        taskService.setAssignee(newCurrentTask.getId(), historicTaskInstance.getAssignee());
        // 无需模拟工作流，当单据再次被申请时，会模拟工作流
        return task.getId();
    }

    @Override
    public Map<String, Object> getTaskInfoByFormId(String businessKey) {
        if (businessKey == null) {
            return null;
        }
        Map<String, Object> map = new HashMap<>();
        HistoricProcessInstance historicProcessInstance = historyService
                .createHistoricProcessInstanceQuery()
                .includeProcessVariables()
                .processInstanceBusinessKey(businessKey)
                .singleResult();

        if (historicProcessInstance == null) {
            return null;
        }
        Map<String, Object> processVariables = historicProcessInstance.getProcessVariables();
        // 处理暂存
        if (!processVariables.containsKey(USER_TASK_INFO_KEY)) {
            return null;
        }
        List<UserTaskPOJO> userTaskList = workFlowHelper.getUserTaskListInProcessVariable(processVariables);

        // 判断流程是否完成
        Date endTime = historicProcessInstance.getEndTime();
        if (endTime != null) {
            WorkflowProcessListHelper helper = new WorkflowProcessListHelper(userTaskList, workFlowHelper, historicProcessInstance.getId());
            if (helper.canBackToStash(userService.getCurrentUser().getId())) {
                map.put(CAN_BACK_TO_STASH, 1);
            } else {
                map.put(CAN_BACK_TO_STASH, 0);
            }
            map.put(USER_TASK_INFO_KEY, userTaskList);
        } else {
            // 流转单据
            // 不查询工作流表了 直接通过维护的链表进行判断
            WorkflowProcessListHelper helper = new WorkflowProcessListHelper(userTaskList, workFlowHelper, historicProcessInstance.getId());
            UserTaskPOJO nextNode = helper.getNextNode();
            // 能否撤回
            //if (helper.isRollBackBeforeSign()){
            //    map.put(CAN_ROLL_BACK, 2);
            //} else if (helper.canRollBack(userService.getCurrentUser().getId())){
            //    map.put(CAN_ROLL_BACK, 1);
            //}
            //if (helper.canRollBack(userService.getCurrentUser().getId())) {
            //} else {
            //    map.put(CAN_ROLL_BACK, 0);
            //}

            map.put(CAN_ROLL_BACK, helper.getRollBackState(userService.getCurrentUser().getId()));

            if (helper.canTurnBack(userService.getCurrentUser().getId())) {
                map.put(CAN_TURN_BACK, 1);
            } else {
                map.put(CAN_TURN_BACK, 0);
            }

            // fix 当审批到最后一个节点，并且退回到经办人 nextNode为空的情况，没有审批要素
            if (nextNode != null) {
                // 审批要素
                //List<ApprovalPoints> approvalPointsList = approvalPointsService
                //        .getByUserTaskIdOrderBySerialNumber(nextNode.getTaskDefineId(), historicProcessInstance.getProcessDefinitionKey());
                //map.put(APPROVAL_POINTS_LIST_KEY, approvalPointsList);

                List<Privilege> privilegeList = privilegeService
                        .getPrivilegeByTaskDefineIdModelKey(nextNode.getTaskDefineId(), historicProcessInstance.getProcessDefinitionKey());
                if (privilegeList != null && privilegeList.size() > 0) {
                    map.put(WorkflowConstant.PRIVILEGE_LIST_KEY, privilegeList);
                }
            }

            map.put(USER_TASK_INFO_KEY, userTaskList);
        }
        return map;
    }

    @Override
    public String completeTask(String formId, String comment, Map<String, Object> variables) {
        ProcessInstance processInstance = runtimeService
                .createProcessInstanceQuery()
                .includeProcessVariables()
                .processInstanceBusinessKey(formId)
                .singleResult();
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        List<Task> list = taskService
                .createTaskQuery()
                .processInstanceId(processInstance.getId())
                .list();
        if (list.size() > 1) {
            list.removeIf(
                    item -> item.getScopeType() != null && "before-parent".equals(item.getScopeType())
            );
        }

        Task task = list.get(0);
        String taskId = task.getId();
        if(processVariables.containsKey(SET_NUMBER)){
            runtimeService.setVariable(processInstance.getId(), SET_NUMBER, (int)processVariables.get(SET_NUMBER) + 1);
        }
        taskService.addComment(taskId, task.getProcessInstanceId(), String.valueOf(TaskStateConstant.STATE_AGREE));
        //task.setDescription(String.valueOf(TaskStateConstant.STATE_AGREE));
        //taskService.saveTask(task);

        // 工作流链表维护
        List<UserTaskPOJO> userTaskList = workFlowHelper.getUserTaskListInProcessVariable(runtimeService.getVariable(task.getProcessInstanceId(), USER_TASK_INFO_KEY));
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(userTaskList, workFlowHelper, processInstance.getId());
        List<UserTaskPOJO> userTaskPOJOS;
        if (BooleanUtils.toBoolean((String) variables.get("isBeforeSignReject"))) {
            userTaskPOJOS = helper.beforeSignReject(comment, new UserPOJO(userService.getCurrentUser()));
        } else {
            userTaskPOJOS = helper.agreeOrSubmit(comment, new UserPOJO(userService.getCurrentUser()));
        }
        workFlowHelper.saveUserTaskListIntoVariable(userTaskPOJOS, task.getProcessInstanceId());

        // 认领
        taskService.setAssignee(taskId, userService.getCurrentUser().getId());

        taskService.complete(taskId, null);

        String parentTaskId = task.getParentTaskId();
        if (StringUtils.isNotBlank(parentTaskId)) {
            String tableName = managementService.getTableName(TaskEntity.class);
            String sql = "select count(1) from " + tableName + " where PARENT_TASK_ID_=#{parentTaskId}";
            long subTaskCount = taskService.createNativeTaskQuery().sql(sql).parameter("parentTaskId", parentTaskId).count();
            if (subTaskCount == 0) {
                //处理前后加签的任务
                taskService.resolveTask(parentTaskId);
                TaskEntityImpl taskEntity = (TaskEntityImpl) taskService.createTaskQuery().taskId(parentTaskId).singleResult();
                taskEntity.setScopeType("");
                taskService.saveTask(taskEntity);
            }
        }

        return taskId;
    }

    @Override
    public void beforeAddSign(String formId, String userId, String signedUserId) {
        TaskEntityImpl taskEntity = (TaskEntityImpl) taskService.createTaskQuery().processInstanceBusinessKey(formId).singleResult();
        if (taskEntity != null) {
            String parentTaskId = taskEntity.getParentTaskId();
            if (StringUtils.isBlank(parentTaskId)) {
                taskEntity.setOwner(userId);
                taskEntity.setAssignee(null);
                taskEntity.setCountEnabled(true);
                taskEntity.setScopeType("before-parent");
                taskService.saveTask(taskEntity);
                createSignSubTasks(userId, signedUserId, taskEntity);
            } else {
                throw new MyRuntimeException(new ObjResult("此任务已加签，不能再次加签！"));
            }
        } else {
            throw new MyRuntimeException(new ObjResult("不存在的任务实例，加签失败！"));
        }
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(taskEntity.getProcessInstanceId()).includeProcessVariables().singleResult();
        Map<String, Object> processVariables = processInstance.getProcessVariables();
        List<UserTaskPOJO> taskListInProcessVariable = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(taskListInProcessVariable, workFlowHelper, taskEntity.getProcessInstanceId());
        PageData pageData = new PageData();
        pageData.put("id", signedUserId);
        PageData pd = userService.findbyid(pageData).getPageData();
        List<UserTaskPOJO> pojoList = helper.beforeAddSign(simulationHelper, new UserPOJO(userService.getCurrentUser()), new UserPOJO(pd));
        workFlowHelper.saveUserTaskListIntoVariable(pojoList, taskEntity.getProcessInstanceId());
    }

    private void createSignSubTasks(String userId, String signedUserId, TaskEntityImpl taskEntity) {
        if (StringUtils.isNotBlank(signedUserId)) {
            String parentTaskId = taskEntity.getParentTaskId();
            if (StringUtils.isNotBlank(parentTaskId)) {
                throw new MyRuntimeException(new ObjResult("此节点为前加签节点，不能再次加签！"));
            }
            parentTaskId = taskEntity.getId();
            String finalParentTaskId = parentTaskId;
            //1.创建被加签人的任务列表
            if (StringUtils.isNotBlank(userId)) {
                createSubTask(taskEntity, finalParentTaskId, signedUserId);
            }

            String taskId = taskEntity.getId();
            if (StringUtils.isBlank(taskEntity.getParentTaskId())) {
                //2.创建加签人的任务并执行完毕
                Task task = createSubTask(taskEntity, finalParentTaskId, userId);
                taskId = task.getId();
                taskService.addComment(taskId, taskEntity.getProcessInstanceId(), String.valueOf(TaskStateConstant.STATE_BEFORE_SIGN));
            }
            Task taskInfo = taskService.createTaskQuery().taskId(taskId).singleResult();
            if (null != taskInfo) {
                taskService.complete(taskId);
            }
            //如果是候选人，需要删除运行时候选表种的数据。
            long candidateCount = taskService.createTaskQuery().taskId(parentTaskId).taskCandidateUser(userId).count();
            if (candidateCount > 0) {
                taskService.deleteCandidateUser(parentTaskId, userId);
            }
        }
    }

    /**
     * 创建子任务
     *
     * @param ptask    创建子任务
     * @param assignee 子任务的执行人
     */
    protected TaskEntity createSubTask(TaskEntity ptask, String ptaskId, String assignee) {
        TaskEntity task = null;
        if (ptask != null) {
            task = (TaskEntity) taskService.newTask(UuidUtil.get32UUID());
            task.setCategory(ptask.getCategory());
            task.setDescription(ptask.getDescription());
            task.setTenantId(ptask.getTenantId());
            task.setAssignee(assignee);
            task.setName(ptask.getName());
            task.setParentTaskId(ptaskId);
            task.setProcessDefinitionId(ptask.getProcessDefinitionId());
            task.setProcessInstanceId(ptask.getProcessInstanceId());
            task.setTaskDefinitionKey(ptask.getTaskDefinitionKey());
            task.setTaskDefinitionId(ptask.getTaskDefinitionId());
            task.setPriority(ptask.getPriority());
            task.setCreateTime(new Date());
            task.setScopeType("before-son");
            taskService.saveTask(task);
        }
        return task;
    }

    @Override
    public boolean isFinish(String formId) {
        HistoricProcessInstance historicProcessInstance = historyService
                .createHistoricProcessInstanceQuery()
                .processInstanceBusinessKey(formId)
                .finished()
                .singleResult();
        return historicProcessInstance != null;
    }

    @Override
    public ListResult<PageData> getCompletedTasksByCurrentUserInPage(PageData pageData) {
        try {
            Page page = new Page(true, pageData);
            List<PageData> list = wfCompletedTaskMapper.listPage(page);
            ListResult<PageData> Result = new ListResult<>(CommonCode.SUCCESS);
            Result.setList(list);
            Result.setTotal(page.getTotal());
            return Result;
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            return new ListResult<>(CommonCode.ERROR);
        }
    }

    @Override
    public List<Integer> getFormTypes(PageData pageData) {
        return wfCompletedTaskMapper.getFormTypes(pageData);
    }

    @Override
    public void rollBackBeforeSign(String formId) {
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(formId).includeProcessVariables().singleResult();
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(formId).list();
        for (Task task : taskList) {
            if ("before-parent".equals(task.getScopeType())) {
                TaskEntityImpl taskEntity = (TaskEntityImpl) task;
                taskEntity.setOwner(null);
                taskEntity.setAssignee(null);
                taskEntity.setCountEnabled(true);
                taskEntity.setScopeType("");
                taskService.saveTask(taskEntity);
            } else if ("before-son".equals(task.getScopeType())) {
                taskService.deleteTask(task.getId());
            }
        }

        Map<String, Object> processVariables = processInstance.getProcessVariables();
        runtimeService.setVariable(processInstance.getId(), SET_NUMBER, 0);
        List<UserTaskPOJO> taskListInProcessVariable = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
        WorkflowProcessListHelper helper = new WorkflowProcessListHelper(taskListInProcessVariable, workFlowHelper, processInstance.getProcessInstanceId());
        List<UserTaskPOJO> pojoList;
        try {
            pojoList = helper.rollBackBeforeSign(simulationHelper, processInstance);
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult("撤回前加签操作时，维护工作流链表失败！"));
        }
        workFlowHelper.saveUserTaskListIntoVariable(pojoList, processInstance.getProcessInstanceId());
    }

    @Override
    public void goBackToStash(String formId, int formType) {
        //根据formId获取历史流程实例
        HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(formId).includeProcessVariables().singleResult();

        if(null == processInstance){
            throw new MyRuntimeException(new ObjResult("该单据历史流程未找到！"));
        }
        Map<String, Object> processVariables = processInstance.getProcessVariables();

        String startUserId = processInstance.getStartUserId();

        //删除流程实例
        historyService.deleteHistoricProcessInstance(processInstance.getId());

        //开启新流程
        //校验历史流程是否删除
        List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery().processInstanceBusinessKey(formId).list();
        if (list.size() > 0) {
            throw new MyRuntimeException(new ObjResult("原历史流程并未删除"));
        }
        startProcessInstanceForBackToStash(formId, formType, processVariables, startUserId);
        ProcessInstance newProcessInstance = runtimeService
                .createProcessInstanceQuery()
                .processInstanceBusinessKey(formId)
                .singleResult();
        LinkedList<UserTaskPOJO> newProcess;
        try {
            newProcess = simulationHelper.simulation(newProcessInstance, processVariables, true);
        } catch (Exception e) {
            log.error(ExceptionUtils.getFullStackTrace(e));
            throw new MyRuntimeException(new ObjResult("保存单据模拟流程异常！"));
        }
        List<UserTaskPOJO> oldProcess = workFlowHelper.getUserTaskListInProcessVariable(processVariables);
        UserTaskPOJO last = oldProcess.get(oldProcess.size() - 1);
        last.setTaskState(TaskStateConstant.STATE_BACK_TO_STASH);
        last.setFinishTime(new Date());
        PageData pageData = new PageData();
        pageData.put("id", TokenUtil.getTokenUserId());
        last.setUserList(new ArrayList<>(1));
        last.setUserPOJO(new UserPOJO(userService.findbyid(pageData).getPageData()));
        UserTaskPOJO first = newProcess.get(0);
        PageData pageData01 = new PageData();
        pageData01.put("id", startUserId);
        first.setUserList(new ArrayList<>(1));
        first.setUserPOJO(new UserPOJO(userService.findbyid(pageData01).getPageData()));
        oldProcess.addAll(newProcess);
        workFlowHelper.saveUserTaskListIntoVariable(oldProcess, newProcessInstance.getId());
        List<Task> taskList = taskService.createTaskQuery().processInstanceBusinessKey(formId).active().list();
        if (taskList.size() != 1) {
            throw new MyRuntimeException(new ObjResult("反审核失败！"));
        }
        Task task = taskList.get(0);
        taskService.setAssignee(task.getId(), startUserId);
    }

    @Override
    public void deleteUnknowReceipts() {
        //获取所有的流程实例
        List<HistoricProcessInstance> historicProcessInstanceList = historyService
                .createHistoricProcessInstanceQuery()
                .list();
        historicProcessInstanceList.forEach(historicProcessInstance -> {
            Integer formType = (Integer) historyService
                    .createHistoricVariableInstanceQuery()
                    .processInstanceId(historicProcessInstance.getId())
                    .variableName("formType")
                    .singleResult()
                    .getValue();
            List<PageData> l = workFlowFormService.get(formType, historicProcessInstance.getBusinessKey(), null);
            if (l.size() == 0) {
                ProcessInstance processId = runtimeService.createProcessInstanceQuery().processInstanceId(historicProcessInstance.getId()).singleResult();
                if (processId != null) {
                    runtimeService.deleteProcessInstance(historicProcessInstance.getId(), "");
                }
                historyService.deleteHistoricProcessInstance(historicProcessInstance.getId());

            }
        });
    }

    @Override
    public List<TaskWithForm> listPage(List<TaskWithForm> allList, PageData pd) {
        Page page = new Page(true, pd);
        int startIndex = (page.getPageNumber() - 1) * page.getPageSize();
        int pageTotal = page.getPageNumber() * page.getPageSize();
        if (allList.size() < pageTotal) {
            return allList.subList(startIndex, allList.size());
        } else {
            return allList.subList(startIndex, pageTotal);
        }
    }

    @Override
    public void updateVariablesAllInfo() {
        List<ProcessInstance> processInstanceList = runtimeService
                .createProcessInstanceQuery()
                .list();

        for (ProcessInstance processInstance : processInstanceList) {
            CompletableFuture.runAsync(() -> {
                Map<String, Object> variablesMap = runtimeService.createProcessInstanceQuery()
                        .processInstanceId(processInstance.getId()).includeProcessVariables().singleResult().getProcessVariables();
                if (isFinish(processInstance.getBusinessKey())) {
                    return;
                }
                if (!variablesMap.containsKey(FORM_TYPE)) {
                    return;
                }
                Integer formType = (Integer) variablesMap.get(FORM_TYPE);
                List<PageData> pageDataList = new ArrayList<>();
                try {
                    pageDataList = workFlowFormService.get(formType, processInstance.getBusinessKey(), null);
                } catch (Exception e) {
                    log.error(ExceptionUtils.getFullStackTrace(e));
                }
                if (CollectionUtil.isNotEmpty(pageDataList)) {
                    PageData formInfo = pageDataList.get(0);
                    pdToVariables(formInfo, variablesMap, processInstance.getStartUserId());
                    runtimeService.setVariables(processInstance.getId(), variablesMap);
                }
            });
        }

    }

    private void pdToVariables(PageData formInfo, Map<String, Object> variablesMap, String startUserId){
        if (formInfo.containsKey(UNIT_NAME)){
            variablesMap.put(UNIT_NAME, formInfo.getString(UNIT_NAME));
        }

        if (StringUtil.isNotBlank(startUserId)){
            variablesMap.put(APPLICANT_NAME, userService.getNameById(startUserId));
            variablesMap.put(APPLICANT_ID, startUserId);
        }
        if (formInfo.containsKey(APPLY_ORGANIZATION_ID)){
            variablesMap.put(APPLY_ORGANIZATION_ID, formInfo.getString(APPLY_ORGANIZATION_ID));
        }
        if (formInfo.containsKey(ORG_NAME)){
            variablesMap.put(ORG_NAME, formInfo.getString(ORG_NAME));
        }
        if (formInfo.containsKey(SALARY_TYPE)){
            variablesMap.put(SALARY_TYPE, formInfo.getString(SALARY_TYPE));
        }
        if (formInfo.containsKey(SALARY_TYPE)){
            variablesMap.put(SALARY_TYPE, formInfo.getString(SALARY_TYPE));
        }
        if (formInfo.containsKey(YEAR)){
            variablesMap.put(YEAR, formInfo.getString(YEAR));
        }
        if (formInfo.containsKey(CODE)){
            variablesMap.put(CODE, formInfo.getString(CODE));
        }
        if (formInfo.containsKey(TABLE)){
            variablesMap.put(TABLE, formInfo.getString(TABLE));
        }
        if (formInfo.containsKey(VEHICLE_DISPOSAL)){
            variablesMap.put(VEHICLE_DISPOSAL, formInfo.getString(VEHICLE_DISPOSAL));
        }

    }
}
